package com.superbytecode.redis.aspect;

import com.superbytecode.redis.annotation.RedisCacheExpire;
import com.superbytecode.redis.wrapper.RedisCacheExpireHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * All rights Reserved, Designed By www.super-bytecode.com
 *
 * @ProjectName: superbytecode-beacon
 * @Package: com.superbytecode.framework.redis.aspect
 * @ClassName: RedisCacheExpireAspect
 * @Description: [缓存失效时间Aspect]
 * <p>
 * 注意顺序要先于CacheInterceptor，否则过期时间读取不到
 * </p>
 * @Author: [Lance Ting]
 * @Date: 2023/11/17 18:31
 * @Version: V1.0
 * @Copyright: 2023 www.super-bytecode.com Inc. All rights reserved.
 * TODO: 注意,本文件Lance Ting所作,如果转载或使用请标明具体出处!
 **/
@Slf4j
@Component
@Aspect
@Order(-1)
public class RedisCacheExpireAspect {


    /**
     * 设置方法对应的缓存过期时间
     *
     * @param joinPoint   切面
     * @param cacheExpire 缓存过期时间
     * @return 直接结果
     * @throws Throwable 异常
     */
    @Around("@annotation(cacheExpire)")
    public Object around(ProceedingJoinPoint joinPoint, RedisCacheExpire cacheExpire) throws Throwable {
        // 过期时间（毫秒）
        long cacheExpiredMilliseconds = 1000L * cacheExpire.value();
        // 上下浮动范围（毫秒）
        long driftRadiusMilliseconds = cacheExpiredMilliseconds == 0 //
                ? 0L //
                : (long) (1000 * RandomUtils.nextDouble(0, cacheExpire.driftRadius()));
        //设置失效时间，加上随机浮动值防止缓存穿透
        RedisCacheExpireHolder.setCacheExpire(cacheExpiredMilliseconds + driftRadiusMilliseconds);
        try {
            return joinPoint.proceed();
        } finally {
            // 清除对象
            RedisCacheExpireHolder.removeCacheExpire();
        }
    }
}